# include "jam.h"
# include "hash.h"
# include "filesys.h"
# include "pathsys.h"
# include "timestamp.h"
# include "newstr.h"

# define BIND_SCANNED 0x01
# define BIND_INIT  0
# define BIND_NOENTRY 1
# define BIND_SPOTTED 2
# define BIND_MISSING 3
# define BIND_FOUND 4

typedef struct _binding BINDING;

struct _binding {
  const char  *name;
  short   flags;
  short progress;
  time_t time;
};

static struct hash *bindhash = 0;
static void time_enter( void *, const char *, int, time_t );

static const char *time_progress[] = {
  "INIT",
  "NOENTRY",
  "SPOTTED",
  "MISSING",
  "FOUND"
};

void timestamp( char *target, time_t *time ) {
  PATHNAME f1, f2;
  BINDING binding, *b = &binding;
  char buf[ MAXJPATH ];
  if( !bindhash ) {
    bindhash = hashinit( sizeof( BINDING ), "bindings" );
  }
  b->name = target;
  b->time = b->flags = 0;
  b->progress = BIND_INIT;
  if( hashenter( bindhash, ( HASHDATA ** )&b ) ) {
    b->name = newstr( target );
  }
  if( b->progress != BIND_INIT ) {
    goto afterscanning;
  }
  b->progress = BIND_NOENTRY;
  path_parse( target, &f1 );
  {
    BINDING binding, *b = &binding;
    f2 = f1;
    f2.f_grist.len = 0;
    path_parent( &f2 );
    path_build( &f2, buf, 0 );
    b->name = buf;
    b->time = b->flags = 0;
    b->progress = BIND_INIT;
    if( hashenter( bindhash, ( HASHDATA ** )&b ) ) {
      b->name = newstr( buf );
    }
    if( !( b->flags & BIND_SCANNED ) ) {
      file_dirscan( buf, time_enter, bindhash );
      b->flags |= BIND_SCANNED;
    }
  }
  if( f1.f_member.len ) {
    BINDING binding, *b = &binding;
    f2 = f1;
    f2.f_grist.len = 0;
    f2.f_member.len = 0;
    path_build( &f2, buf, 0 );
    b->name = buf;
    b->time = b->flags = 0;
    b->progress = BIND_INIT;
    if( hashenter( bindhash, ( HASHDATA ** )&b ) ) {
      b->name = newstr( buf );
    }
    if( !( b->flags & BIND_SCANNED ) ) {
      file_archscan( buf, time_enter, bindhash );
      b->flags |= BIND_SCANNED;
    }
  }
afterscanning:
  if( b->progress == BIND_SPOTTED ) {
    if( file_time( b->name, &b->time ) < 0 ) {
      b->progress = BIND_MISSING;
    } else
    { b->progress = BIND_FOUND; }
  }
  *time = b->progress == BIND_FOUND ? b->time : 0;
}

static void time_enter( void *closure, const char *target, int found, time_t time ) {
  BINDING binding, *b = &binding;
  struct hash *bindhash = ( struct hash * )closure;
  b->name = target;
  b->flags = 0;
  if( hashenter( bindhash, ( HASHDATA ** )&b ) ) {
    b->name = newstr( target );
  }
  b->time = time;
  b->progress = found ? BIND_FOUND : BIND_SPOTTED;
  if( DEBUG_BINDSCAN ) {
    printf( "time ( %s ) : %s\n", target, time_progress[b->progress] );
  }
}

void donestamps() {
  hashdone( bindhash );
  bindhash = 0;
}
